/**
 * Copyright 2006 Brad Reynolds
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.leeloo.databinding.internal.ui;

import java.io.BufferedWriter;
import java.io.OutputStreamWriter;
import java.net.Socket;

import org.leeloo.databinding.ui.test.support.PluginTestCase;

public class TraceServerTest extends PluginTestCase {
	TraceServer server;

	protected void setUp() throws Exception {
		server = new TraceServer();
	}

	protected void tearDown() throws Exception {
		if (server != null && server.isRunning()) {
			server.stop();
		}
	}

	public void testStart() throws Exception {
		assertFalse(server.isRunning());
		server.start();
		assertTrue(server.isRunning());
	}
    
    public void testMultipleStarts() throws Exception {
        server.start();
        assertTrue(server.isRunning());
        
        try {
            server.start();
            fail("exception should have been thrown");
        } catch (IllegalStateException e) {
        }
    }

	public void testStop() throws Exception {
		server.start();

		assertTrue(server.isRunning());
		server.stop();
		assertFalse(server.isRunning());
	}

	public void testHasConnections() throws Exception {
		server.start();
		assertFalse(server.hasConnections());

		Socket socket = null;

		socket = new Socket((String) null, server.getLocalPort());
		Thread.sleep(100);

		assertTrue(server.hasConnections());
		socket.close();
	}
	
	public void testTraceEvents() throws Exception {
		server.start();
		
		TraceListener listener = new TraceListener();
		server.addTraceListener(listener);
		
		Socket socket = null;
		BufferedWriter out = null;
		try {
			socket = new Socket((String) null, server.getLocalPort());
			out = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
			assertEquals(0, listener.count);
			
			String className = "myclassname";
			String methodName = "mymethodname";
			int milliseconds = 1;
			int sequence = 2;
			String loggerName = "mylogger";
			int level = 3;
			int threadID = 4;
			String message = "my message";
			
			StringBuffer buffer = new StringBuffer();
			buffer.append("<record>\n");
			appendElement(buffer, "millis", milliseconds);
			appendElement(buffer, "sequence", sequence);
			appendElement(buffer, "logger", loggerName);
			appendElement(buffer, "class", className);
			appendElement(buffer, "method", methodName);
			appendElement(buffer, "thread", threadID);
			appendElement(buffer, "message", message);
			buffer.append("</record>\n");
			
			out.write(buffer.toString());
			out.flush();
			
			Thread.sleep(100);
			
			assertEquals(1, listener.count);
			assertEquals("milliseconds", milliseconds, listener.message.getMilliseconds());
			assertEquals("sequence", sequence, listener.message.getSequence());
			assertEquals("loggerName", loggerName, listener.message.getLoggerName());
			assertEquals("className", className, listener.message.getClassName());
			assertEquals("methodName", methodName, listener.message.getMethodName());
			assertEquals("threadID", threadID, listener.message.getThreadID());
			assertEquals("message", message, listener.message.getMessage());			
		} finally {
			if (out != null) {
				out.close();
			}
			
			if (out != null) {
				socket.close();
			}
		}
	}
    
    /**
     * Asserts that multiple servers can be running at once (e.g. multiple instances of Eclipse).
     * @throws Exception
     */
    public void testMultipleInstances() throws Exception {
        TraceServer server1 = null;
        TraceServer server2 = null;
        
        try {
            server1 = new TraceServer();
            server1.start();
            assertTrue(server1.isRunning());
            assertTrue(server1.getLocalPort() > 0);
            
            server2 = new TraceServer();
            server2.start();
            assertTrue(server2.isRunning());
            assertTrue(server2.getLocalPort() > 0);
            
            assertTrue(server1.getLocalPort() != server2.getLocalPort());
        } catch (Exception e) {
            fail(e.getMessage());
        } finally {
            if (server1 != null) {
                server1.stop();
            }
            
            if (server2 != null) {
                server2.stop();
            }
        }
    }
	
	private StringBuffer appendElement(StringBuffer buffer, String name, String value) {
		return buffer.append("<").append(name).append(">").append(value).append("</").append(name).append(">\n");
	}
	
	private StringBuffer appendElement(StringBuffer buffer, String name, int value) {
		return appendElement(buffer, name, Integer.toString(value));
	}
    
    private static class TraceListener implements ITraceListener {
        int count;
        LogMessage message;

        public void message(LogMessage message) {
            count++;
            this.message = message;
        }       
    }
}
